home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-2.iso / os2 / rsynth1.zip / text.c < prev    next >
C/C++ Source or Header  |  1994-11-08  |  9KB  |  360 lines

  1. #include <config.h>
  2. /* $Id: text.c,v 1.13 1994/11/08 13:30:50 a904209 Exp a904209 $
  3.  */
  4. char *text_id = "$Id: text.c,v 1.13 1994/11/08 13:30:50 a904209 Exp a904209 $";
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <useconfig.h>
  8. #include "proto.h"
  9. #include "darray.h"
  10. #include "phtoelm.h"
  11. #include "text.h"
  12. #include "say.h"
  13.  
  14. #define FALSE (0)
  15. #define TRUE (!0)
  16.  
  17. /*
  18.    **      English to Phoneme translation.
  19.    **
  20.    **      Rules are made up of four parts:
  21.    **
  22.    **              The left context.
  23.    **              The text to match.
  24.    **              The right context.
  25.    **              The phonemes to substitute for the matched text.
  26.    **
  27.    **      Procedure:
  28.    **
  29.    **              Seperate each block of letters (apostrophes included)
  30.    **              and add a space on each side.  For each unmatched
  31.    **              letter in the word, look through the rules where the
  32.    **              text to match starts with the letter in the word.  If
  33.    **              the text to match is found and the right and left
  34.    **              context patterns also match, output the phonemes for
  35.    **              that rule and skip to the next unmatched letter.
  36.    **
  37.    **
  38.    **      Special Context Symbols:
  39.    **
  40.    **              #       One or more vowels
  41.    **              :       Zero or more consonants
  42.    **              ^       One consonant.
  43.    **              .       One of B, D, V, G, J, L, M, N, R, W or Z (voiced
  44.    **                      consonants)
  45.    **              %       One of ER, E, ES, ED, ING, ELY (a suffix)
  46.    **                      (Right context only)
  47.    **              +       One of E, I or Y (a "front" vowel)
  48.  */
  49.  
  50.  
  51. typedef char *Rule[4];            /* A rule is four character pointers */
  52. extern Rule *Rules[];             /* An array of pointers to rules */
  53.  
  54. int
  55. isvowel(chr)
  56. int chr;
  57. {
  58.  return (chr == 'A' || chr == 'E' || chr == 'I' ||
  59.          chr == 'O' || chr == 'U');
  60. }
  61.  
  62. int
  63. isconsonant(chr)
  64. int chr;
  65. {
  66.  return (isupper(chr) && !isvowel(chr));
  67. }
  68.  
  69. static int leftmatch PROTO((char *pattern, char *context));
  70.  
  71. static int
  72. leftmatch(pattern, context)
  73. char *pattern;                    /* first char of pattern to match in text */
  74. char *context;                    /* last char of text to be matched */
  75. {
  76.  char *pat;
  77.  char *text;
  78.  int count;
  79.  if (*pattern == '\0')
  80.   /* null string matches any context */
  81.   {
  82.    return TRUE;
  83.   }
  84.  
  85.  /* point to last character in pattern string */
  86.  count = strlen(pattern);
  87.  pat = pattern + (count - 1);
  88.  text = context;
  89.  for (; count > 0; pat--, count--)
  90.   {
  91.    /* First check for simple text or space */
  92.    if (isalpha(*pat) || *pat == '\'' || *pat == ' ')
  93.     if (*pat != *text)
  94.      return FALSE;
  95.     else
  96.      {
  97.       text--;
  98.       continue;
  99.      }
  100.    switch (*pat)
  101.     {
  102.      case '#':                   /* One or more vowels */
  103.       if (!isvowel(*text))
  104.        return FALSE;
  105.       text--;
  106.       while (isvowel(*text))
  107.        text--;
  108.       break;
  109.      case ':':                   /* Zero or more consonants */
  110.       while (isconsonant(*text))
  111.        text--;
  112.       break;
  113.      case '^':                   /* One consonant */
  114.       if (!isconsonant(*text))
  115.        return FALSE;
  116.       text--;
  117.       break;
  118.      case '.':                   /* B, D, V, G, J, L, M, N, R, W, Z */
  119.       if (*text != 'B' && *text != 'D' && *text != 'V'
  120.           && *text != 'G' && *text != 'J' && *text != 'L'
  121.           && *text != 'M' && *text != 'N' && *text != 'R'
  122.           && *text != 'W' && *text != 'Z')
  123.        return FALSE;
  124.       text--;
  125.       break;
  126.      case '+':                   /* E, I or Y (front vowel) */
  127.       if (*text != 'E' && *text != 'I' && *text != 'Y')
  128.        return FALSE;
  129.       text--;
  130.       break;
  131.      case '%':
  132.      default:
  133.       fprintf(stderr, "Bad char in left rule: '%c'\n", *pat);
  134.       return FALSE;
  135.     }
  136.   }
  137.  return TRUE;
  138. }
  139.  
  140. static int rightmatch PROTO((char *pattern, char *context));
  141.  
  142. static int
  143. rightmatch(pattern, context)
  144. char *pattern;                    /* first char of pattern to match in text */
  145. char *context;                    /* last char of text to be matched */
  146. {
  147.  char *pat;
  148.  char *text;
  149.  if (*pattern == '\0')
  150.   /* null string matches any context */
  151.   return TRUE;
  152.  pat = pattern;
  153.  text = context;
  154.  for (pat = pattern; *pat != '\0'; pat++)
  155.   {
  156.    /* First check for simple text or space */
  157.    if (isalpha(*pat) || *pat == '\'' || *pat == ' ')
  158.     if (*pat != *text)
  159.      return FALSE;
  160.     else
  161.      {
  162.       text++;
  163.       continue;
  164.      }
  165.    switch (*pat)
  166.     {
  167.      case '#':                   /* One or more vowels */
  168.       if (!isvowel(*text))
  169.        return FALSE;
  170.       text++;
  171.       while (isvowel(*text))
  172.        text++;
  173.       break;
  174.      case ':':                   /* Zero or more consonants */
  175.       while (isconsonant(*text))
  176.        text++;
  177.       break;
  178.      case '^':                   /* One consonant */
  179.       if (!isconsonant(*text))
  180.        return FALSE;
  181.       text++;
  182.       break;
  183.      case '.':                   /* B, D, V, G, J, L, M, N, R, W, Z */
  184.       if (*text != 'B' && *text != 'D' && *text != 'V'
  185.           && *text != 'G' && *text != 'J' && *text != 'L'
  186.           && *text != 'M' && *text != 'N' && *text != 'R'
  187.           && *text != 'W' && *text != 'Z')
  188.        return FALSE;
  189.       text++;
  190.       break;
  191.      case '+':                   /* E, I or Y (front vowel) */
  192.       if (*text != 'E' && *text != 'I' && *text != 'Y')
  193.        return FALSE;
  194.       text++;
  195.       break;
  196.      case '%':                   /* ER, E, ES, ED, ING, ELY (a suffix) */
  197.       if (*text == 'E')
  198.        {
  199.         text++;
  200.         if (*text == 'L')
  201.          {
  202.           text++;
  203.           if (*text == 'Y')
  204.            {
  205.             text++;
  206.             break;
  207.            }
  208.           else
  209.            {
  210.             text--;               /* Don't gobble L */
  211.             break;
  212.            }
  213.          }
  214.         else if (*text == 'R' || *text == 'S' || *text == 'D')
  215.          text++;
  216.         break;
  217.        }
  218.       else if (*text == 'I')
  219.        {
  220.         text++;
  221.         if (*text == 'N')
  222.          {
  223.           text++;
  224.           if (*text == 'G')
  225.            {
  226.             text++;
  227.             break;
  228.            }
  229.          }
  230.         return FALSE;
  231.        }
  232.       else
  233.        return FALSE;
  234.      default:
  235.       fprintf(stderr, "Bad char in right rule:'%c'\n", *pat);
  236.       return FALSE;
  237.     }
  238.   }
  239.  return TRUE;
  240. }
  241.  
  242. static int find_rule PROTO((void *arg, out_p out, char *word, int index, Rule(*rules)));
  243.  
  244. static int
  245. find_rule(arg, out, word, index, rules)
  246. void *arg;
  247. out_p out;
  248. char *word;
  249. int index;
  250. Rule(*rules);
  251. {
  252.  Rule *rule;
  253.  char *left,
  254.      *match,
  255.      *right,
  256.      *output;
  257.  int remainder;
  258.  for (;;)                         /* Search for the rule */
  259.   {
  260.    rule = rules++;
  261.    match = (*rule)[1];
  262.    if (match == 0)
  263.     /* bad symbol! */
  264.     {
  265.      fprintf(stderr, "Error: Can't find rule for: '%c' in \"%s\"\n",
  266.              word[index], word);
  267.      return index + 1;            /* Skip it! */
  268.     }
  269.    for (remainder = index; *match != '\0'; match++, remainder++)
  270.     {
  271.      if (*match != word[remainder])
  272.       break;
  273.     }
  274.    if (*match != '\0')
  275.     continue;                     /* found missmatch */
  276.  
  277.    /*
  278.       printf("\nWord: \"%s\", Index:%4d, Trying: \"%s/%s/%s\" = \"%s\"\n",
  279.       word, index, (*rule)[0], (*rule)[1], (*rule)[2], (*rule)[3]);
  280.     */
  281.    left = (*rule)[0];
  282.  
  283.    right = (*rule)[2];
  284.  
  285.    if (!leftmatch(left, &word[index - 1]))
  286.     continue;
  287.  
  288.    /* printf("leftmatch(\"%s\",\"...%c\") succeded!\n", left, word[index-1]); */
  289.    if (!rightmatch(right, &word[remainder]))
  290.     continue;
  291.  
  292.    /* printf("rightmatch(\"%s\",\"%s\") succeded!\n", right, &word[remainder]); */
  293.    output = (*rule)[3];
  294.  
  295.    /* printf("Success: "); */
  296.    (*out) (arg, output);
  297.    return remainder;
  298.   }
  299. }
  300.  
  301. static void guess_word PROTO((void *arg, out_p out, char *word));
  302.  
  303. static void
  304. guess_word(arg, out, word)
  305. void *arg;
  306. out_p out;
  307. char *word;
  308. {
  309.  int index;                       /* Current position in word */
  310.  int type;                        /* First letter of match part */
  311.  index = 1;                       /* Skip the initial blank */
  312.  do
  313.   {
  314.    if (isupper(word[index]))
  315.     type = word[index] - 'A' + 1;
  316.    else
  317.     type = 0;
  318.    index = find_rule(arg, out, word, index, Rules[type]);
  319.   }
  320.  while (word[index] != '\0');
  321. }
  322.  
  323.  
  324. static void phone_cat PROTO((void *arg, char *s));
  325.  
  326. static void
  327. phone_cat(arg, s)
  328. void *arg;
  329. char *s;
  330. {
  331.  darray_ptr p = (darray_ptr) arg;
  332.  char ch;
  333.  while ((ch = *s++))
  334.   phone_append(p, ch);
  335. }
  336.  
  337. int
  338. NRL(s, n, phone)
  339. char *s;
  340. unsigned n;
  341. darray_ptr phone;
  342. {
  343.  int old = phone->items;
  344.  char *word = (char *) malloc(n + 3);
  345.  char *d = word;
  346.  *d++ = ' ';
  347.  while (n-- > 0)
  348.   {
  349.    char ch = *s++;
  350.    if (islower(ch))
  351.     ch = toupper(ch);
  352.    *d++ = ch;
  353.   }
  354.  *d++ = ' ';
  355.  *d = '\0';
  356.  guess_word(phone, phone_cat, word);
  357.  free(word);
  358.  return phone->items - old;
  359. }
  360.